home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Our Solar System
/
Our Solar System.iso
/
shuttle
/
seesat3
/
util.c
< prev
Wrap
Text File
|
1990-12-24
|
12KB
|
455 lines
/*
UTIL.C
Paul S. Hirose, 1990 Nov 12
User interface support functions for SEESAT satellite tracking program.
100 - 199
Library functions and #defines used in this file:
atof, atoi, getchar, isalpha, isspace, NULL, printf, strcmp, strcpy,
strlen, toupper.
*/
#include "b:seesat.h" /* global header */
extern void printf();
extern int atoi(), getchar(), isalpha(), isspace(),
strcmp(), strlen(), toupper();
extern char *strcpy();
extern double atof();
/* Use 0 for normal operation. Non-zero will make static functions & data
externally visible for testing */
#define NSTAT 0
#if NSTAT /* test mode */
#define STATIC /* precedes static definitions of functions & data */
#define SC extern /* precedes declarations of static functions */
#else /* normal mode */
#define STATIC static
#define SC static
#endif
/*############################## DATA ##############################*/
struct month {
char *mname; /* month name */
int difm; /* days in full months */
};
/* calendar */
STATIC struct month calndr[] = {
{"JAN", 0}, {"FEB", 31}, {"MAR", 59},
{"APR", 90}, {"MAY", 120}, {"JUN", 151},
{"JUL", 181}, {"AUG", 212}, {"SEP", 243},
{"OCT", 273}, {"NOV", 304}, {"DEC", 334}, {NULL, 365}
};
/*################ FUNCTIONS LOCAL TO THIS FILE ################*/
SC void cpy0p(); /* strncpy() with leading 0 padding */
SC int leapyr(); /* returns 1 if arg is leap year */
SC char *s_in(); /* input a string with prompt */
/*############################## CODE ##############################*/
double
atomin(string)
char *string;
/* Returns value (in minutes) of string of form "hhmm:ss.s...". Leading
minus sign permitted. */
{
double time;
char *ptr, c, buf[5];
int sign;
if (*string == '-') {
sign = -1;
++string;
} else
sign = 1;
ptr = string;
/* point to the colon (or terminating null if no colon) */
while ((c = *ptr) && c != ':')
++ptr;
/* process seconds */
if (c) { /* string had a colon */
time = atof(ptr + 1) / 60.;
*ptr = '\0'; /* turn ':' to '\0' */
} else
time = 0.;
cpy0p(buf, string, 5); /* buf[] = "hhmm" */
time += atof(buf + 2); /* add minutes */
buf[2] = '\0';
/* add hours, restore sign */
return (time + atof(buf) * 60.) * sign;
}
STATIC void
cpy0p(dest, src, n)
char *dest, *src;
int n;
/* Copy n-1 chars from src[] to dest[]. If src[] is too short, pad dest[]
with leading '0's. If src[] is too long, not all of src[] will be copied.
dest[] will always receive n-1 chars followed by null terminator. */
{
int i, len;
len = strlen(src);
for (i = n; --i; )
*dest++ = (i > len) ? '0' : *src++;
*dest = '\0';
}
char **
degdms(pre, x)
int pre; /* precision */
double x;
/* Converts x degrees to 3 strings holding degrees, minutes, seconds. "pre"
specifies rounding and may be 0 - 4: 0 = nearest deg, 1 = nearest 10 min, 2
= 1 min, 3 = 10 sec, 4 = 1 sec. Domain of x (after rounding): -1000 < x <
10000. Returns pointer to dms[]. If pre was 1 or 2, s[] is garbage. Both
s[] & m[] are garbage if pre was 0. */
{
long int lx;
int sign;
static int mult[] = {1, 6, 60, 360, 3600};
static char
d[5], m[3], sec[3],
*dms[] = {d, m, sec};
if (x >= 0.)
sign = 1;
else {
sign = -1;
x = -x;
}
lx = (long) (x * mult[pre] + .5) * (((unsigned) pre & 1) ? 10 : 1);
switch (pre) {
case 4:
case 3:
ITOA(sec, (int) (lx % 60)); /* seconds */
lx /= 60;
case 2:
case 1:
ITOA(m, (int) (lx % 60)); /* minutes */
lx /= 60;
}
ITOA(d, (int) lx * sign); /* degrees */
return dms;
}
double
din(str)
char *str;
/* Input a double, with default value. Sends '[', str, then "]: " to the
console. Then waits for user input. If a only a carriage return is struck,
returns str converted to a double. If a string is typed, returns the string
converted to double. Backspacing is allowed. */
{
char buffer[30];
printf("[%s]:", str);
if (strlen(s_in(" ", buffer)))
return atof(buffer);
else
return atof(str);
}
char *
jdstr(jd)
long int jd; /* Julian Date, unit = days */
/* Converts jd to Gregorian calendar date. Good for both BC & AD for
practically any date one might want. More precisely, domain of jd is limited
by largest/smallest year an int can hold, as well as size of buffer[].
Returns pointer to year/month/day string, e.g., "1990 JAN 14". */
{
static char buffer[13]; /* space for -yyyy mmm dd */
struct month *calp; /* pointer into calendar */
int d, m, n;
int leap; /* flag; 1 = leap yr */
char *cp;
/* 1721425 = Julian Date @ 1 BC Dec 31 (Gregorian calendar), 12h UT.
365.2425 = days per year (over the 400 yr Gregorian cycle). */
n = (jd - 1721425) / 365.2425;
if (n >= 0)
++n;
/* n = estimated year. Correct the estimate to actual year. The
preceding formula can mistakenly yield an AD year from a BC jd, but
the reverse will never happen. Therefore, we need only guard against
n being DECREMENTED to 0 (which is an undefined year). */
while (1) {
d = jd - julday(n, 0, 0);
leap = leapyr(n); /* true if leap year */
if (d <= 365 + leap && d >= 1)
break;
if (d < 1) {
--n;
if (n == 0)
--n; /* skip year 0 */
} else
++n;
}
ITOA(buffer, n); /* write the year */
cp = buffer + strlen(buffer);
*cp++ = ' ';
/* determine month by moving forward thru the calendar till we
overshoot, then back up one month */
calp = calndr; /* point to Jan */
m = 0; /* month counter; 0 = Jan */
do {
n = (++calp)->difm;
if (++m >= 2) /* March or later */
n += leap;
} while (d > n);
d -= (--calp)->difm + (m >= 2 && leap);
/* write month & day */
strcpy(cp, calp->mname);
cp += 3;
*cp++ = ' ';
ITOA(cp, d);
return buffer;
}
long int
julday(y, m, d)
int y, m, d; /* year, month (Jan = 0), day */
/* Returns Julian Date (unit = days) corresponding to 12h UT on given date,
Gregorian calendar. Jan = month 0. Use -1 for 1 BC, etc. Any integer
is legal for d. */
{
int bc; /* flag; 1 = BC */
if (m > 1) /* after Feb */
d += leapyr(y); /* add 1 if leap yr */
if (y >= 0) {
--y;
bc = 0;
} else {
y = -(y + 1);
bc = 1;
}
return ((bc ? 366 : 0) + y*365L + y/4 - y/100 + y/400) *
(bc ? -1 : 1) + calndr[m].difm + d + 1721425;
/* 1721425 = Julian Date for 1 BC Dec 31 12h, Gregorian calendar */
}
STATIC int
leapyr(y)
int y;
/* Returns 1 if y is leap year in Gregorian calendar, 0 otherwise. To
signify BC year use a negative number, e.g., -1 for 1 BC. */
{
/* For leap year determination purposes, 1 BC = 0, 2 BC = -1, etc.
Therefore, we must make an adjustment to y if it's BC. */
if (y < 0)
++y;
return !(y%4) && y%100 || !(y%400);
}
char *
stoup(string)
char *string;
/* Converts "string" to all upper case, returns "string". */
{
char *cp;
int i;
for (cp = string; i = *cp; ++cp)
if (isalpha(i))
*cp = toupper(i);
return string;
}
STATIC char *
s_in(prompt, buffer)
char *prompt, *buffer;
/* Prints prompt[] on console, puts typed string in buffer[]. Backspacing
will correct typing mistakes. Will not allow backspacing past the start of
buffer. Returns pointer to buffer. */
{
static char c, *ptr, last;
for (ptr = prompt; *ptr; ++ptr)
; /* point to terminating null of prompt */
last = *(ptr - 1); /* fetch char before the null */
printf("%s", prompt);
ptr = buffer;
while ((c = getchar()) != '\n')
if (c == '\b')
if (ptr == buffer)
printf("%c", last);
else
--ptr;
else
*ptr++ = c;
*ptr = '\0';
return buffer;
}
char *
timstr(m)
double m; /* minutes */
/* Turns m into a string of format "hhmm:ss" (or "-hhmm:ss" if m is
negative), rounded to nearest second. Be sure that hours will not require
more than two digits. String will be padded with zeros to fill out all six
digits. Returns the string. */
{
static char buf[9];
char *cp, **cpp;
int minus; /* flag; 1 = negative */
cp = buf;
cpp = degdms(4, m / 60.);
if (m < 0.) {
*cp++ = '-';
minus = 1;
} else
minus = 0;
cpy0p(cp, cpp[0] + minus, 3);
cpy0p(cp + 2, cpp[1], 3);
cp[4] = ':';
cpy0p(cp + 5, cpp[2], 3);
return buf;
}
void
tok()
/* tok() prompts user with '>' and accepts a string. String is converted to
upper case. Each ' ' in the string is replaced with '\0' & successive
members of tokens[] point to the sub-strings ("tokens") thus created. A
character sequence containing spaces is considered a single token if it's
enclosed in quotes (the quotes will not become part of the token). End of
tokens[] is marked by NULL. On exit, tokp points to tokens[0]. */
{
char *cptr;
char c;
int notok; /* flag; 1 = not in a token */
static char
*tokens[20], /* pointers to cmd line tokens */
buffer[85]; /* command line buffer */
/* display '>', accept command line */
s_in(">", buffer);
stoup(buffer);
cptr = buffer - 1;
tokp = tokens; /* point to 1st element of tokens[] */
notok = 1; /* set "not in token" flag true */
while (c = *++cptr) /* tokenize the command line */
if (isspace(c)) {
notok = 1;
*cptr = '\0'; /* replace ' ' with '\0' */
} else if (notok) { /* first char of a token */
if (c != '"')
*tokp++ = cptr;
else { /* quoted token */
*tokp++ = ++cptr;
while (*++cptr != '"')
; /* find closing '"' */
*cptr = '\0';
} notok = 0;
}
*tokp = NULL; /* terminate tokens[] */
tokp = tokens;
}
void
tokjum(t)
struct jdtim *t;
/* Converts command line arguments (pointed to by global "tokp") into Julian
Date & minutes. NO conversion to UTC occurs! tokp[1] thru [4] = {year,
month, day, time}. Month must be first 3 letters of name. Year, month, or
day may be omitted if the arguments to its left are also omitted. On exit,
tokp will point to next item following the arguments. Returns JD & minutes
in struct "t". */
{
static int date[3]; /* default year, month (Jan = 0), day */
struct month *calp; /* pointer into calendar */
int m, n;
char *cp, **cpp;
/* Set n to # of date arguments. Can be 0 - 3. */
/* point cpp to next arg beginning with a letter, or end of cmd line,
whichever comes first */
for (cpp = tokp + 1; (cp = *cpp) && !isalpha(*cp); ++cpp)
;
if (cp == NULL) /* reached end of command line */
n = cpp - tokp - 2;
else { /* is cp[] a month name? */
for (calp = calndr + 11, m = 11; m >= 0 &&
strcmp(cp, calp->mname); --calp, --m)
; /* look for cp[] in calendar */
/* if m >= 0 it's a month name, otherwise it's next cmd */
n = cpp - tokp + ((m >= 0) ? 1 : -2);
} if (n > 3 || n < 0) {
printf("%s: INCORRECT ARGUMENTS\n", *tokp);
LONGJMP(reset, 1);
}
/* if year, month, or day were given, set them as new defaults */
switch (n) {
case 3:
date[0] = atoi(*++tokp); /* year */
case 2:
date[1] = m; /* month */
++tokp;
case 1:
date[2] = atoi(*++tokp); /* day */
}
if (date[0] == 0) { /* year = 0, i.e., full date not given yet */
printf("DATE HAS NOT BEEN SET\n");
LONGJMP(reset, 1);
}
/* compute Julian Date & time of day */
t->jd = julday(date[0], date[1], date[2]);
t->time = atomin(*++tokp);
++tokp; /* point to next cmd line token */
}
double
tokmin()
/* Same as tokjum() except returns epoch expressed as minutes instead of
Julian Date & minutes, and the time zone is Greenwich. */
{
struct jdtim t;
tokjum(&t);
return t.jd * xmnpda - 720. + t.time + zd;
}
--m)
; /* look for cp[] in calendar */
/* if m >= 0 it's a month name, otherwise it's next cmd */
n